<template>
  <div class="range-picker-panel">
    <!-- 左边日历 -->
    <div class="mini-calendar">
      <!-- 年份选择面板 -->
      <template v-if="showYearLeftPicker">
        <div class="picker-header">
          <button class="btn-prev-year" @click="changeYearRange(-10)">
            <el-icon><d-arrow-left /></el-icon>
          </button>
          <span>{{ yearRangeStart }} - {{ yearRangeStart + 9 }}</span>
          <button class="btn-next-year" @click="changeYearRange(10)">
            <el-icon><d-arrow-right /></el-icon>
          </button>
        </div>
        <div class="picker-content">
          <div
            v-for="year in yearRange"
            :key="year"
            class="picker-cell"
            :class="{
              'is-current': year === today.year(),
              'is-selected': isSelectedYear(year),
            }"
            @click="selectLeftYear(year)"
          >
            {{ year }}
          </div>
        </div>
      </template>
      <!-- 月份选择面板 -->
      <template v-else-if="showMonthLeftPicker">
        <div class="picker-header">
          <button class="btn-prev" @click="changeYear(-1)">
            <el-icon><arrow-left /></el-icon>
          </button>
          <span @click="showYearLeftPicker = true" class="year-text">{{
            currentMonth.year()
          }}</span>
          <button class="btn-next" @click="changeYear(1)">
            <el-icon><arrow-right /></el-icon>
          </button>
        </div>
        <div class="picker-content">
          <div
            v-for="(_, index) in 12"
            :key="index"
            class="picker-cell"
            :class="{
              'is-current':
                index === today.month() && currentMonth.year() === today.year(),
              'is-selected': isSelectedLeftMonth(index),
            }"
            @click="selectLeftMonth(index)"
          >
            {{ index + 1 }}月
          </div>
        </div>
      </template>
      <template v-else>
        <!-- 日历头部 -->
        <div class="calendar-header">
          <div class="calendar-header-btn-wrapper">
            <button class="btn-prev-year" @click="prevYear">
              <el-icon><d-arrow-left /></el-icon>
            </button>
            <button class="btn-prev" @click="prevMonth">
              <el-icon><arrow-left /></el-icon>
            </button>
          </div>
          <span class="current-date">
            <!-- 将年月拆分为可点击的部分 -->
            <span class="year-text" @click="showYearLeftPicker = true"
              >{{ currentMonth.format('YYYY') }} 年</span
            >
            <span class="month-text" @click="showMonthLeftPicker = true"
              >{{ currentMonth.format('MM') }} 月</span
            >
          </span>
          <div class="calendar-header-btn-wrapper"></div>
        </div>
        <!-- 星期 -->
        <div class="calendar-weeks">
          <span v-for="day in weekDays" :key="day" class="week-day">{{
            day
          }}</span>
        </div>
        <!-- 日期 -->
        <div class="calendar-days">
          <div
            v-for="day in currentMonthDays"
            :key="day.date.valueOf()"
            class="picker-cell"
            :class="{
              'is-today': day.isToday,
              'is-selected': isSelectedDay(day.date),
              'is-in-range': isInRange(day.date) || isInHoverRange(day.date),
              'range-start': isRangeStartStyle(day.date),
              'range-end': isRangeEndStyle(day.date),
              'not-current-month': !day.currentMonth,
            }"
            @click="selectDate(day.date)"
            @mouseenter="handleMouseEnter(day.date)"
            @mouseleave="handleMouseLeave"
          >
            {{ day.dayOfMonth }}
          </div>
        </div>
      </template>
    </div>
    <!-- 右边日历 -->
    <div class="mini-calendar">
      <!-- 年份选择面板 -->
      <template v-if="showYearRightPicker">
        <div class="picker-header">
          <button class="btn-prev-year" @click="changeYearRange(-10)">
            <el-icon><d-arrow-left /></el-icon>
          </button>
          <span>{{ yearRangeStart }} - {{ yearRangeStart + 9 }}</span>
          <button class="btn-next-year" @click="changeYearRange(10)">
            <el-icon><d-arrow-right /></el-icon>
          </button>
        </div>
        <div class="picker-content">
          <div
            v-for="year in yearRange"
            :key="year"
            class="picker-cell"
            :class="{
              'is-current': year === today.year(),
              'is-selected': isSelectedYear(year),
            }"
            @click="selectRightYear(year)"
          >
            {{ year }}
          </div>
        </div>
      </template>
      <!-- 月份选择面板 -->
      <template v-else-if="showMonthRightPicker">
        <div class="picker-header">
          <button class="btn-prev" @click="changeYear(-1)">
            <el-icon><arrow-left /></el-icon>
          </button>
          <span @click="showYearRightPicker = true" class="year-text">{{
            currentMonth.year()
          }}</span>
          <button class="btn-next" @click="changeYear(1)">
            <el-icon><arrow-right /></el-icon>
          </button>
        </div>
        <div class="picker-content">
          <div
            v-for="(_, index) in 12"
            :key="index"
            class="picker-cell"
            :class="{
              'is-current':
                index === today.month() && currentMonth.year() === today.year(),
              'is-selected': isSelectedRightMonth(index),
            }"
            @click="selectRightMonth(index)"
          >
            {{ index + 1 }}月
          </div>
        </div>
      </template>
      <template v-else>
        <!-- 日历头部 -->
        <div class="calendar-header">
          <div class="calendar-header-btn-wrapper"></div>
          <span class="current-date">
            <!-- 将年月拆分为可点击的部分 -->
            <span class="year-text" @click="showYearRightPicker = true"
              >{{ currentMonth.add(1, 'month').format('YYYY') }} 年</span
            >
            <span class="month-text" @click="showMonthRightPicker = true"
              >{{ currentMonth.add(1, 'month').format('MM') }} 月</span
            >
          </span>
          <div class="calendar-header-btn-wrapper">
            <button class="btn-next" @click="nextMonth">
              <el-icon><arrow-right /></el-icon>
            </button>
            <button class="btn-next-year" @click="nextYear">
              <el-icon><d-arrow-right /></el-icon>
            </button>
          </div>
        </div>
        <!-- 星期 -->
        <div class="calendar-weeks">
          <span v-for="day in weekDays" :key="day" class="week-day">{{
            day
          }}</span>
        </div>
        <!-- 日期 -->
        <div class="calendar-days">
          <div
            v-for="day in nextMonthDays"
            :key="day.date.valueOf()"
            class="picker-cell"
            :class="{
              'is-today': day.isToday,
              'is-selected': isSelectedDay(day.date),
              'is-in-range': isInRange(day.date) || isInHoverRange(day.date),
              'range-start': isRangeStartStyle(day.date),
              'range-end': isRangeEndStyle(day.date),
              'not-current-month': !day.currentMonth,
            }"
            @click="selectDate(day.date)"
            @mouseenter="handleMouseEnter(day.date)"
            @mouseleave="handleMouseLeave"
          >
            {{ day.dayOfMonth }}
          </div>
        </div>
      </template>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, watch, onMounted } from 'vue'
import dayjs from 'dayjs'
import { isArray, isString } from 'lodash-es'

const props = defineProps(['initDate'])

// 今天
const today = dayjs()

// 当前展示的月份
const currentMonth = ref(dayjs())

// 范围选择状态
const rangeStart = ref(null)
const rangeEnd = ref(null)
// 鼠标悬浮的日期
const hoverDate = ref(null)

// 年份选择和月份选择的状态
const showYearLeftPicker = ref(false)
const showMonthLeftPicker = ref(false)
const showYearRightPicker = ref(false)
const showMonthRightPicker = ref(false)

// 年份范围起始年
const yearRangeStart = computed(() => {
  return Math.floor(currentMonth.value.year() / 10) * 10
})
// 年份范围数组
const yearRange = computed(() => {
  return Array.from({ length: 10 }, (_, i) => yearRangeStart.value + i)
})

// 星期几标题
const weekDays = ['日', '一', '二', '三', '四', '五', '六']

// 计算当前月所有要展示的日期（包括上/下月的溢出部分）
const currentMonthDays = computed(() => {
  const date = currentMonth.value
  const year = date.year()
  const month = date.month()

  // 当月第一天是星期几 (0-6)
  const firstDayOfMonth = dayjs(new Date(year, month, 1))
  const firstDayWeekday = firstDayOfMonth.day()

  // 当月有多少天
  const daysInMonth = date.daysInMonth()

  // 日期数组
  const daysArray = []

  // 添加上月溢出的日期
  const prevMonth = month === 0 ? 11 : month - 1
  const prevMonthYear = month === 0 ? year - 1 : year
  const prevMonthDays = dayjs(
    new Date(prevMonthYear, prevMonth, 1)
  ).daysInMonth()

  for (let i = 0; i < firstDayWeekday; i++) {
    const day = prevMonthDays - firstDayWeekday + i + 1
    daysArray.push({
      date: dayjs(new Date(prevMonthYear, prevMonth, day)),
      dayOfMonth: day,
      currentMonth: false,
      isToday: dayjs(new Date(prevMonthYear, prevMonth, day)).isSame(
        dayjs(),
        'day'
      ),
    })
  }

  // 添加当月日期
  const today = dayjs()
  for (let i = 1; i <= daysInMonth; i++) {
    const date = dayjs(new Date(year, month, i))
    daysArray.push({
      date,
      dayOfMonth: i,
      currentMonth: true,
      isToday: date.isSame(today, 'day'),
    })
  }

  // 添加下月溢出的日期
  const daysNeeded = 42 - daysArray.length // 6行 x 7列 = 42个格子
  const nextMonth = month === 11 ? 0 : month + 1
  const nextMonthYear = month === 11 ? year + 1 : year

  for (let i = 1; i <= daysNeeded; i++) {
    const date = dayjs(new Date(nextMonthYear, nextMonth, i))
    daysArray.push({
      date,
      dayOfMonth: i,
      currentMonth: false,
      isToday: date.isSame(today, 'day'),
    })
  }

  return daysArray
})

const nextMonthDays = computed(() => {
  const date = currentMonth.value.add(1, 'month')
  const year = date.year()
  const month = date.month()

  // 当月第一天是星期几 (0-6)
  const firstDayOfMonth = dayjs(new Date(year, month, 1))
  const firstDayWeekday = firstDayOfMonth.day()

  // 当月有多少天
  const daysInMonth = date.daysInMonth()

  // 日期数组
  const daysArray = []

  // 添加上月溢出的日期
  const prevMonth = month === 0 ? 11 : month - 1
  const prevMonthYear = month === 0 ? year - 1 : year
  const prevMonthDays = dayjs(
    new Date(prevMonthYear, prevMonth, 1)
  ).daysInMonth()

  for (let i = 0; i < firstDayWeekday; i++) {
    const day = prevMonthDays - firstDayWeekday + i + 1
    daysArray.push({
      date: dayjs(new Date(prevMonthYear, prevMonth, day)),
      dayOfMonth: day,
      currentMonth: false,
      isToday: dayjs(new Date(prevMonthYear, prevMonth, day)).isSame(
        dayjs(),
        'day'
      ),
    })
  }

  // 添加当月日期
  const today = dayjs()
  for (let i = 1; i <= daysInMonth; i++) {
    const date = dayjs(new Date(year, month, i))
    daysArray.push({
      date,
      dayOfMonth: i,
      currentMonth: true,
      isToday: date.isSame(today, 'day'),
    })
  }

  // 添加下月溢出的日期
  const daysNeeded = 42 - daysArray.length // 6行 x 7列 = 42个格子
  const nextMonth = month === 11 ? 0 : month + 1
  const nextMonthYear = month === 11 ? year + 1 : year

  for (let i = 1; i <= daysNeeded; i++) {
    const date = dayjs(new Date(nextMonthYear, nextMonth, i))
    daysArray.push({
      date,
      dayOfMonth: i,
      currentMonth: false,
      isToday: date.isSame(today, 'day'),
    })
  }

  return daysArray
})

// 鼠标进入日期单元格
const handleMouseEnter = (date) => {
  if (rangeStart.value && !rangeEnd.value) {
    hoverDate.value = date
  }
}
// 鼠标离开日期单元格
const handleMouseLeave = () => {
  hoverDate.value = null
}

// 检查日期是否在悬停范围内
const isInHoverRange = (date) => {
  if (!rangeStart.value || !hoverDate.value || rangeEnd.value) return false

  // 根据悬停位置确定范围
  if (hoverDate.value.isBefore(rangeStart.value)) {
    return date.isAfter(hoverDate.value) && date.isBefore(rangeStart.value)
  } else {
    return date.isAfter(rangeStart.value) && date.isBefore(hoverDate.value)
  }
}

// 修改年份范围
const changeYearRange = (offset) => {
  currentMonth.value = currentMonth.value.year(yearRangeStart.value + offset)
}

// 修改年份
const changeYear = (offset) => {
  currentMonth.value = currentMonth.value.add(offset, 'year')
}
// 选择年份
const selectLeftYear = (year) => {
  currentMonth.value = currentMonth.value.year(year)
  showYearLeftPicker.value = false
  showMonthLeftPicker.value = true
}
const selectRightYear = (year) => {
  currentMonth.value = currentMonth.value.year(year)
  showYearRightPicker.value = false
  showMonthRightPicker.value = true
}
// 选择月份
const selectLeftMonth = (month) => {
  currentMonth.value = currentMonth.value.month(month)
  showMonthLeftPicker.value = false
}
const selectRightMonth = (month) => {
  currentMonth.value = currentMonth.value.month(month).subtract(1, 'month')
  showMonthRightPicker.value = false
}

// 切换到上个月
const prevMonth = () => {
  currentMonth.value = currentMonth.value.subtract(1, 'month')
}

// 切换到下个月
const nextMonth = () => {
  currentMonth.value = currentMonth.value.add(1, 'month')
}

// 切换到上一年
const prevYear = () => {
  currentMonth.value = currentMonth.value.subtract(1, 'year')
}
// 切换到下一年
const nextYear = () => {
  currentMonth.value = currentMonth.value.add(1, 'year')
}

// 选择日期
const selectDate = (date) => {
  if (
    !date.isSame(currentMonth.value, 'month') &&
    !date.isSame(currentMonth.value.add(1, 'month'), 'month')
  ) {
    // 更新当前月份以显示所点击日期的月份
    if (date.isAfter(currentMonth.value.add(1, 'month'))) {
      currentMonth.value = date.subtract(1, 'month')
    } else if (date.isBefore(currentMonth.value)) {
      currentMonth.value = date
    }
  }
  // 处理范围选择
  if (!rangeStart.value || rangeEnd.value !== null) {
    // 开始新范围
    rangeStart.value = date
    rangeEnd.value = null
  } else {
    // 完成范围选择
    if (date.isBefore(rangeStart.value)) {
      rangeEnd.value = rangeStart.value
      rangeStart.value = date
    } else {
      rangeEnd.value = date
    }
  }
}

// 判断年份是否被选中
const isSelectedYear = (year) => {
  return currentMonth.value.year() === year
}

// 判断月份是否被选中
const isSelectedLeftMonth = (month) => {
  return currentMonth.value.month() === month
}
const isSelectedRightMonth = (month) => {
  return currentMonth.value.add(1, 'month').month() === month
}

// 检查日期是否在所选范围内
const isInRange = (date) => {
  if (!rangeStart.value || !rangeEnd.value) return false
  return (
    date.isAfter(rangeStart.value) &&
    date.isBefore(rangeEnd.value) &&
    !date.isSame(rangeStart.value, 'day') &&
    !date.isSame(rangeEnd.value, 'day')
  )
}

// 检查日期是否为范围开始
const isRangeStart = (date) => {
  return rangeStart.value && date.isSame(rangeStart.value, 'day')
}

// 检查日期是否为范围结束
const isRangeEnd = (date) => {
  return rangeEnd.value && date.isSame(rangeEnd.value, 'day')
}
// 判断日期是否被选中
const isSelectedDay = (date) => {
  return isRangeStart(date) || isRangeEnd(date)
}

// 新增两个方法来确定应该应用什么样式
const isRangeStartStyle = (date) => {
  // 如果已经完成范围选择
  if (rangeStart.value && rangeEnd.value) {
    return date.isSame(rangeStart.value, 'day')
  }

  // 如果正在进行悬停
  if (rangeStart.value && hoverDate.value && !rangeEnd.value) {
    // 如果悬停日期在选中日期之前
    if (hoverDate.value.isBefore(rangeStart.value)) {
      return date.isSame(hoverDate.value, 'day') // 悬停日期成为视觉上的起点
    } else {
      return date.isSame(rangeStart.value, 'day') // 选中日期依然是起点
    }
  }

  // 只有起点没有终点且没有悬停
  return rangeStart.value && date.isSame(rangeStart.value, 'day')
}

const isRangeEndStyle = (date) => {
  // 如果已经完成范围选择
  if (rangeStart.value && rangeEnd.value) {
    return date.isSame(rangeEnd.value, 'day')
  }

  // 如果正在进行悬停
  if (rangeStart.value && hoverDate.value && !rangeEnd.value) {
    // 如果悬停日期在选中日期之前
    if (hoverDate.value.isBefore(rangeStart.value)) {
      return date.isSame(rangeStart.value, 'day') // 选中日期成为视觉上的终点
    } else {
      return date.isSame(hoverDate.value, 'day') // 悬停日期是终点
    }
  }

  return false // 其他情况没有终点样式
}

const setValue = (start, end) => {
  hoverDate.value = null
  rangeStart.value = start
  rangeEnd.value = end
  if (!start.isSame(currentMonth.value, 'month')) {
    currentMonth.value = start
  }
}

const getValue = () => {
  if (!rangeStart.value || !rangeEnd.value) return null
  return [rangeStart.value, rangeEnd.value]
}

const initState = () => {
  if (!props.initDate || !isArray(props.initDate)) return
  const [start, end] = props.initDate
  if (
    isString(start) &&
    dayjs(start, 'YYYY-MM-DD', true).isValid() &&
    isString(end) &&
    dayjs(end, 'YYYY-MM-DD', true).isValid()
  ) {
    currentMonth.value = dayjs(start)
    rangeStart.value = dayjs(start)
    rangeEnd.value = dayjs(end)
  }
}

const reset = () => {
  currentMonth.value = dayjs()
  rangeStart.value = null
  rangeEnd.value = null
}

onMounted(() => {
  initState()
})

watch(
  () => props.initDate,
  () => {
    initState()
  },
  {
    once: true,
  }
)

defineExpose({
  setValue,
  getValue,
  reset,
})
</script>

<style scoped>
.range-picker-panel {
  display: inline-flex;
}
.mini-calendar {
  width: 300px;
  background-color: #fff;
  padding: 12px;
  font-size: 14px;
}

.calendar-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 10px;
  padding-bottom: 8px;
  border-bottom: 1px solid #ebeef5;
}

.calendar-header-btn-wrapper {
  width: 52px;
}

.current-date {
  font-size: 16px;
  color: #606266;
}

.btn-prev,
.btn-next,
.btn-prev-year,
.btn-next-year {
  border: none;
  background: transparent;
  cursor: pointer;
  padding: 6px;
  color: #606266;
  border-radius: 50%;
}

.btn-prev:hover,
.btn-next:hover,
.btn-prev-year:hover,
.btn-next-year:hover {
  color: #409eff;
}

.calendar-weeks {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  margin-bottom: 6px;
}

.week-day {
  text-align: center;
  color: #606266;
  font-size: 12px;
  padding: 5px 0;
}

.calendar-days {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  row-gap: 8px;
}

.is-today {
  color: #409eff;
  font-weight: bold;
}

.year-text,
.month-text {
  cursor: pointer;
  padding: 0 2px;
}
.year-text:hover,
.month-text:hover {
  color: #409eff;
}
.picker-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 0;
  margin-bottom: 8px;
}
.picker-content {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  row-gap: 8px;
  padding: 8px 0;
}
.picker-cell {
  text-align: center;
  height: 30px;
  line-height: 30px;
  cursor: pointer;
  border-radius: 4px;
}
.picker-cell:hover {
  color: #409eff;
}
.picker-cell.is-current {
  color: #409eff;
  font-weight: bold;
}
.picker-cell.is-selected {
  background-color: #409eff;
  color: white;
  font-weight: bold;
}

.picker-cell.is-selected:hover {
  background-color: #409eff;
  opacity: 0.9;
}

/* 范围选择样式 */
.is-in-range {
  background-color: #ecf5ff;
  border-radius: 0;
}

.range-start,
.range-end {
  background-color: #409eff;
  color: white;
  font-weight: bold;
}

.range-start {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}

.range-end {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
}

.picker-cell.range-end:hover,
.picker-cell.range-start:hover {
  color: white;
}

.picker-cell.range-start.range-end {
  border-radius: 4px;
}

.picker-cell.not-current-month,
.picker-cell.not-current-month:hover {
  color: #c0c4cc;
  background: #ffffff;
  font-weight: normal;
}
</style>
